/*
* runimg c/c++ sdk
* Copyright 2015 guangleihe@gmail.com.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http ://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include <iostream>
#include <map>
#include "base/logging.h"
#include "runimg/runimgservice.h"
#include <Windows.h>
#include <sstream>

const char HTML_VIEW_HEADER[] = "<!DOCTYPE html>"
                                "<html>"
                                "<head>"
                                "<meta charset=\"utf-8\">"
                                "<title>runimg test</title>"
                                "</head>"
                                "<body>";

const char HTML_VIEW_END[]   = "</body>"
                               "</html>";

const char SPARE_LINE[] = "<HR style=\"FILTER: alpha(opacity=100,finishopacity=0,style=1)\" color=#987cb9 SIZE=3>";

// http://192.168.48.141/uploadservices/index.php/lastupdate?
// http://www.runimg.com/services.php/lastupdate?
const char DEBUG_BASE_URL[] = "http://www.runimg.com/services.php/lastupdate?";
// const char DEBUG_BASE_URL[] = "http://192.168.48.141/uploadservices/index.php/lastupdate?";

void OpenUrl(LPCSTR url, bool isDefaultIe) {
  if(isDefaultIe) {
    HINSTANCE result = ::ShellExecute(NULL, NULL, "iexplore.exe", url, NULL, SW_SHOW);
    if ((int)result <= HINSTANCE_ERROR)
      result = ::ShellExecute(NULL, "open", url, NULL, NULL, SW_SHOW);
  } else {
    HINSTANCE result = ::ShellExecute(NULL, "open", url, NULL, NULL, SW_SHOW);
    if ((int)result <= HINSTANCE_ERROR)
      result = ::ShellExecute(NULL, NULL, "iexplore.exe", url, NULL, SW_SHOW);
  }
}
// -----------------------------------------------------------------------------

std::string TempPath() {
  DWORD dwRetVal = 0;
  TCHAR path_buffer[MAX_PATH];
  // Check the process return
  dwRetVal = GetTempPath(MAX_PATH, path_buffer);
  return path_buffer;
}

// -----------------------------------------------------------------------------

typedef void(*ProcessFunc)(runimg::ImageOperator::Ptr image_operator,
                           std::string *case_name);

struct TestSetting {
  ProcessFunc process_func;
  std::string test_name;
  runimg::UpdateStanza result_stanza;
};

// =============================================================================

void ZoomTest01(runimg::ImageOperator::Ptr  image_operator,
                std::string *case_name) {
  *case_name = "image_operator->SetImageZoom(50)";
  // image_operator->SetImageZoom(256, 512);
  image_operator->SetImageZoom(50);
}

void ZoomTest02(runimg::ImageOperator::Ptr  image_operator,
                std::string *case_name) {
  *case_name = "SetImageZoom(256, 512, true)";
  image_operator->SetImageZoom(256, 512, true);
}

void ImageClipperTest01(runimg::ImageOperator::Ptr  image_operator,
                        std::string *case_name) {
  *case_name = "SetImageClipper(128, 128, 1)";
  image_operator->SetImageClipper(128, 128, 1);
}

void ImageClipperTest02(runimg::ImageOperator::Ptr  image_operator,
                        std::string *case_name) {
  *case_name = "SetImageClipper(272 * 4, runimg::ClipperType::MIN_SQUARE)";
  image_operator->SetImageClipper(272 * 4, runimg::ClipperType::MIN_SQUARE);
}

void ImageClipperTest03(runimg::ImageOperator::Ptr  image_operator,
                        std::string *case_name) {
  *case_name = "SetImageClipper(225, runimg::ClipperDirect::CLIPPER_X, 1)";
  image_operator->SetImageClipper(225, runimg::ClipperDirect::CLIPPER_X, 1);
}

void ImageClipperTest04(runimg::ImageOperator::Ptr  image_operator,
                        std::string *case_name) {
  *case_name = "SetImageClipper(225, 225, 16, 16)";
  image_operator->SetImageClipper(225, 225, 16, 16);
}


void ImageRotatorTest01(runimg::ImageOperator::Ptr  image_operator,
                        std::string *case_name) {
  *case_name = "SetImageRotator(180)";
  image_operator->SetImageRotator(180);
}


void ImageSharpenTest01(runimg::ImageOperator::Ptr  image_operator,
                        std::string *case_name) {
  *case_name = "SetImageSharpen(180)";
  image_operator->SetImageSharpen(180);
}


void ImageBlurryTest01(runimg::ImageOperator::Ptr  image_operator,
                       std::string *case_name) {
  *case_name = "SetImageBlurry(25, 25)";
  image_operator->SetImageBlurry(25, 25);
}

void ImageBrightnessTest01(runimg::ImageOperator::Ptr  image_operator,
                           std::string *case_name) {
  *case_name = "SetImageBrightness(50";
  image_operator->SetImageBrightness(50);
}

void ImageContrastTest01(runimg::ImageOperator::Ptr  image_operator,
                         std::string *case_name) {
  *case_name = "SetImageContrast(50)";
  image_operator->SetImageContrast(50);
}

// http://192.168.48.141/uploadservices/index.php/lastupdate?
// http://192.168.48.141/uploadservices/index.php/lastupdate?expired=3600&img_opt=eyJmb3JtYXQiOiJibXAifQo%3D&img_type=1d&rec_inv=eyJldCI6MCwic3QiOjB9Cg%3D%3D&signature=j9mKAw6fX56xStRDwZc90%2BVuXZo%3D&timestamp=1462610328&token_id=123456789ABCDEF0&version=1.0

void ImageFormatTest01(runimg::ImageOperator::Ptr  image_operator,
                       std::string *case_name) {
  *case_name = "SetImageFormat(runimg::FORMAT_BMP)";
  image_operator->SetImageFormat(runimg::FORMAT_BMP);
}
void ImageFormatTest02(runimg::ImageOperator::Ptr  image_operator,
                       std::string *case_name) {
  *case_name = "SetImageFormat(runimg::FORMAT_GIT)";
  image_operator->SetImageFormat(runimg::FORMAT_GIT);
}
void ImageFormatTest03(runimg::ImageOperator::Ptr  image_operator,
                       std::string *case_name) {
  *case_name = "SetImageFormat(runimg::FORMAT_JPG)";
  image_operator->SetImageFormat(runimg::FORMAT_JPG);
}
void ImageFormatTest04(runimg::ImageOperator::Ptr  image_operator,
                       std::string *case_name) {
  *case_name = "SetImageFormat(runimg::FORMAT_PNG)";
  image_operator->SetImageFormat(runimg::FORMAT_PNG);
}
void ImageFormatTest05(runimg::ImageOperator::Ptr  image_operator,
                       std::string *case_name) {
  *case_name = "SetImageFormat(runimg::FORMAT_SRC)";
  image_operator->SetImageFormat(runimg::FORMAT_SRC);
}
void ImageFormatTest06(runimg::ImageOperator::Ptr  image_operator,
                       std::string *case_name) {
  *case_name = "SetImageFormat(runimg::FORMAT_WEBP)";
  image_operator->SetImageFormat(runimg::FORMAT_WEBP);
}
// =============================================================================

void SetTestCase(std::vector<TestSetting> &test_settings) {
  TestSetting ts;
  // ---------------------------------------------------------------------------
  ts.process_func = ZoomTest01;
  test_settings.push_back(ts);
  // ---------------------------------------------------------------------------
  ts.process_func = ZoomTest02;
  test_settings.push_back(ts);
  // ---------------------------------------------------------------------------
  ts.process_func = ImageClipperTest01;
  test_settings.push_back(ts);
  // ---------------------------------------------------------------------------
  ts.process_func = ImageClipperTest02;
  test_settings.push_back(ts);
  // ---------------------------------------------------------------------------
  ts.process_func = ImageClipperTest03;
  test_settings.push_back(ts);
  // ---------------------------------------------------------------------------
  ts.process_func = ImageClipperTest04;
  test_settings.push_back(ts);
  // ---------------------------------------------------------------------------
  ts.process_func = ImageRotatorTest01;
  test_settings.push_back(ts);
  // ---------------------------------------------------------------------------
  ts.process_func = ImageSharpenTest01;
  test_settings.push_back(ts);
  // ---------------------------------------------------------------------------
  ts.process_func = ImageBlurryTest01;
  test_settings.push_back(ts);
  // ---------------------------------------------------------------------------
  ts.process_func = ImageBrightnessTest01;
  test_settings.push_back(ts);
  // ---------------------------------------------------------------------------
  ts.process_func = ImageContrastTest01;
  test_settings.push_back(ts);


  // ---------------------------------------------------------------------------
  ts.process_func = ImageFormatTest01;
  test_settings.push_back(ts);
  // ---------------------------------------------------------------------------
  ts.process_func = ImageFormatTest02;
  test_settings.push_back(ts);
  // ---------------------------------------------------------------------------
  ts.process_func = ImageFormatTest03;
  test_settings.push_back(ts);
  // ---------------------------------------------------------------------------
  ts.process_func = ImageFormatTest04;
  test_settings.push_back(ts);
  // ---------------------------------------------------------------------------
  ts.process_func = ImageFormatTest05;
  test_settings.push_back(ts);
  // ---------------------------------------------------------------------------
  ts.process_func = ImageFormatTest06;
  test_settings.push_back(ts);
}

const std::string WriteDataToTempFile(std::string data) {
  std::string temp_path = TempPath();
  temp_path += "view.html";
  FILE *fp = fopen(temp_path.c_str(), "wb");
  if(fp == NULL) {
    LOG(ERROR) << "Failiure to open the fiile " << temp_path;
    return std::string();
  }
  fwrite(data.c_str(), 1, data.size(), fp);
  fclose(fp);
  return temp_path;
}

const std::string GeneratorHtml(std::vector<TestSetting> &test_settings) {
  std::stringstream ss;
  // 1. Add Header
  ss << HTML_VIEW_HEADER;
  for(std::size_t i = 0; i < test_settings.size(); i++) {
    runimg::UpdateStanza &stanza = test_settings[i].result_stanza;
    if(stanza.status != 200) {
      LOG(ERROR) << "The result status is not 200";
      continue;
    }
    if(stanza.records.size() == 0) {
      LOG(ERROR) << "There is no result return";
      continue;
    }
    ss << "<h2>";
    ss << test_settings[i].test_name;
    ss << "</h2>";
    ss << "<img src=\"";
    ss << stanza.records[0].url;
    ss << "\"  alt=\"Failure to Load Image\" />\n";
    ss << SPARE_LINE;
  }
  ss << HTML_VIEW_END;
  return WriteDataToTempFile(ss.str());
}

//const uint32 DEFAULT_VALUE = 0XFFFFFF;
//
//void Dump(std::vector<uint32> &take_record) {
//  for(std::size_t i = 0; i < take_record.size(); i++) {
//    if(take_record[i] != DEFAULT_VALUE) {
//      std::cout << i << " ";
//    } else {
//      std::cout << "  ";
//    }
//  }
//  std::cout << std::endl;
//}
//
//void TakePermutation(std::vector<uint32> &take_record, std::size_t remain_size) {
//  if(!remain_size) {
//    return;
//  }
//  for(std::size_t i = 0; i < take_record.size(); i++) {
//    if(take_record[i] == DEFAULT_VALUE) {
//      take_record[i] = remain_size;
//      Dump(take_record);
//      TakePermutation(take_record, remain_size - 1);
//      take_record[i] = DEFAULT_VALUE;
//    }
//  }
//}

int main(int argv, char* argc[]) {
#ifdef GOOGLE_GLOG_LIBRARY
  google::InitGoogleLogging(argc[0]);
  FLAGS_logtostderr = true;
  FLAGS_stderrthreshold = 0;
  FLAGS_colorlogtostderr = true;
#endif

  //std::vector<uint32> take_record;
  //take_record.push_back(DEFAULT_VALUE);
  //take_record.push_back(DEFAULT_VALUE);
  //take_record.push_back(DEFAULT_VALUE);
  //take_record.push_back(DEFAULT_VALUE);
  //take_record.push_back(DEFAULT_VALUE);

  //TakePermutation(take_record, 5);

  //return EXIT_SUCCESS;

  std::vector<TestSetting> test_settings;
  // ---------------------------------------------------------------------------
  SetTestCase(test_settings);
  // ---------------------------------------------------------------------------

  runimg::ImageOperator::Ptr  image_operator(new runimg::ImageOperator());
  // ---------------------------------------------------------------------------
  // ---------------------------------------------------------------------------
  runimg::UrlCreator::Ptr     url_creator(
    new runimg::UrlCreator("123456789ABCDEF0",
                           "0123456789ABCDEF",
                           runimg::TYPE_1D,
                           36000,
                           image_operator));
  url_creator->SetRecordInterval(0, 0);

  runimg::RunimgService::Ptr runimg_serivce(new runimg::RunimgService());
  for(std::size_t i = 0; i < test_settings.size(); i++) {
    image_operator->Reset();
    // 1. Process Image Settings
    test_settings[i].process_func(image_operator, &test_settings[i].test_name);
    // 2. Get image url
    test_settings[i].result_stanza =
      runimg_serivce->GetImageUrl(DEBUG_BASE_URL, url_creator);
  }
  std::string html_file = GeneratorHtml(test_settings);
  OpenUrl(html_file.c_str(), true);
  return EXIT_SUCCESS;
}